export function patch(oldNode,vnode){
   if(oldNode){
        if(oldNode.nodeType===1){
            //初次对比的时候是要挂载的真实dom元素#app

            //用vnode 生成真实dom替换原来的dom
            let parentEl=oldNode.parentNode
            let elm=createElm(vnode)  //根据虚拟dom对象 创建真实dom结构
            //先将新dom插入到老节点的下方
            parentEl.insertBefore(elm,oldNode.nextSibling)
            //再讲旧节点移除
            parentEl.removeChild(oldNode)
            return elm
        }

        if(oldNode.tag!==vnode.tag){
            //新旧标签不一致
            return oldNode.el.replaceChild(createElm(vnode))   
        }
        //同一个标签时

        //存文本节点
        if(!oldNode.tag){
            if(oldNode.text!==vnode.text){
                oldNode.el.parentNode.innerText=vnode.text
                return oldNode.el
            }
        }
        let el=vnode.el=oldNode.el
        //更新属性
        updateProps(vnode,oldNode)
        let oldChild=oldNode.children||[]
        let newChild=vnode.children||[]
        if(oldChild.length>0&&newChild.length>0){
              diff(oldNode,vnode)
        }else if(oldChild.length>0){
              el.innerHTML=''
        }else if(newChild.length>0){
              for(let child of newChild){
                el.appendChild(createElm(child))
              }
        }
        return oldNode.el
   }else{
        //组件的更新对比
        console.log(vnode,'组件gen更新挂载----------------')
        return createElm(vnode) 
   }

    
    
}

export function createElm(vnode={}){
    let {tag,data,children,text}=vnode
    if(typeof tag ==='string'){
         if(createComponent(vnode)){
             //组件情况
             return vnode.componentInstance.ctor.componentInstance.$el
         }

        //正常的html标签
        vnode.el=document.createElement(tag)
        updateProps(vnode)
        children.forEach(item=>{
           vnode.el.appendChild(createElm(item)) 
        })
    }else{
        //纯文本节点
        vnode.el=document.createTextNode(text)
    }
    return vnode.el
}

function createComponent(vnode){
    //创建组件
    let {componentInstance}=vnode
    if(!componentInstance) return false
    let i=vnode.data
    if(i?.hooks&&i.hooks.init){
        //调用组件挂载
        i.hooks.init(vnode)
    }
    if(componentInstance) return  true
}

function updateProps(vnode,oldNode={}){
   
    let vData=vnode.data||{}
    let oldData=oldNode.data||{}

    for(let key in oldData){
        if(!vData[key]){
            delete oldData.key
        }
    }
    for(let key in vData){
        if(key==='style'){
            vnode.el.setAttribute(key,parseStyle(vData[key]))
        }else if(key==='class'){
            vnode.el.className=vData[key]
        }else{
            vnode.el.setAttribute(key,vData[key]) 
        }
    }
}

function parseStyle(style){
    let str=''
   for(let key in style){
     str+=`${key}:${style[key]};`
   }
   return str
}

function sameNode(oldNode,newNode){
    return oldNode.tag===newNode.tag&&oldNode.key===newNode.key
}

function diff(oldNode,newNode){
  
    let oldStartIndex=0
    let oldStartNode=oldNode.children[oldStartIndex]
    let oldEndIndex=oldNode.children.length-1
    let oldEndNode=oldNode.children[oldEndIndex]

    let newStartIndex=0
    let newStartNode=newNode.children[newStartIndex]
    let newEndIndex=newNode.children.length-1
    let newEndNode=newNode.children[newEndIndex]

    let keyMap=null  //储存乱序时 没有处理的节点key

    while(oldStartIndex<=oldEndIndex&&newStartIndex<=newEndIndex){
        if(!oldStartNode){
            oldStartNode=oldNode.children[++oldStartIndex]
        }else if(!oldEndNode){
            oldEndNode=oldNode.children[--oldEndIndex]
        }else if(sameNode(oldStartNode,newStartNode)){
            patch(oldStartNode,newStartNode)
            oldStartNode=oldNode.children[++oldStartIndex]
            newStartNode=newNode.children[++newStartIndex]
        }else if(sameNode(oldEndNode,newEndNode)){
            patch(oldEndNode,newEndNode)
            oldEndNode=oldNode.children[--oldEndIndex]
            newEndNode=newNode.children[--newEndIndex]
        }else if(sameNode(oldStartNode,newEndNode)){
            patch(oldStartNode,newEndNode)
            oldNode.el.insertBefore(oldStartNode.el,oldEndNode.el.nextSibling)
            oldStartNode=oldNode.children[++oldStartIndex]
            newEndNode=newNode.children[--newEndIndex]
        }else if(sameNode(oldEndNode,newStartNode)){
            patch(oldEndNode,newStartNode)
            oldNode.el.insertBefore(oldEndNode.el,oldStartNode.el)
            oldEndNode=oldNode.children[--oldEndIndex]
            newStartNode=newNode.children[++newStartIndex]
        }else{
            //乱序情况
            if(!keyMap){
                keyMap={}
                for(let i=oldStartIndex;i<=oldEndIndex;i++){
                    oldNode.children.key&&(keyMap[oldNode.children.key]=i)
                }
            }
            let keyIndex=keyMap[newNode.children[newStartIndex].key]
            if(keyIndex){
                //在旧节点中找到了节点，但是发生了位置改变
                let moveNode=oldNode.children[keyIndex]
                patch( moveNode,newStartNode)
                //讲匹配到的节点移到startIndex前面
                oldNode.el.insertBefore(moveNode.el,oldStartNode.el)
                //并将原来节点设置为undefined
                oldNode.el.children[keyIndex]=undefined
            }else{
                //旧节点中没有新节点中的key 说明是新增的节点
                oldNode.el.insertBefore(createElm(newStartNode),oldStartNode.el)
            }
            newStartNode=newNode.children[++newStartIndex]

        }
    }


    for(let i=oldStartIndex;i<=oldEndIndex;i++){
         oldNode.el.removeChild(oldNode.el.children[i].el)
    }

    for(let j=newStartIndex;j<=newEndIndex;j++){
        oldNode.el.appendChild(createElm(newNode.children[j]))
    }
}







